﻿jQuery.fn.jForm = function(opts) {
    opts = jQuery.extend({
        form: '',
        method: '',
        url: '',
        onCancel: null,
        onLoaded: null,
        onProceed: null,
        onSuccess: null,
        coreElement: null,
        messagesElement: null,
        object: null,
        params: null,
        saveButtonText: null,
        ajaxMode: true,
        showSummary: true,
        hiddenFields: null
    }, opts || {});

    requiredResources = [];
    resources = {};

    jForms_RefreshSelect = function(sel) {
        if (!sel) { sel = this; }
        var optionSource = $(sel).attr('rel');

        // Deal with /Enum.Type.Name/['PropertyName' for object
        // or 'Form.PropertyName' for which form field to get the data]
        if (optionSource) {
            if (optionSource.indexOf('/[') > -1) {
                var dataProperty = optionSource.substring(optionSource.indexOf('/[') + 2);
                dataProperty = dataProperty.substring(0, dataProperty.length - 1);
                var propValue = null;
                if (optionSource.indexOf('Form.') > -1) {
                    // Data from form
                    var formField = $(opts.coreElement.find('*[name=' + dataProperty.replace('Form.', '') + ']')[0]);
                    propValue = formField.val();
                    formField.unbind('change', jForms_RefreshDependentSelects);
                    formField.bind('change', jForms_RefreshDependentSelects);
                } else {
                    // Data from the object's property
                    eval('propValue = opts.object.' + dataProperty + ';');
                }
                optionSource = optionSource.substring(0, optionSource.indexOf('/[')) + '/' + propValue;
            }
            if (optionSource && optionSource.length > 0) {
                $(sel).removeOption(/./);
                $(sel).addOption("Loading...", "Loading...");
                $.postJSON('/cms/info/GetOptionList', { source: optionSource }, function(json) {
                    $(sel).removeOption(/./);
                    $(json).each(function(optionIndex, option) {
                        $(sel).addOption(option.id, option.value);
                    });
                    eval('var bPropExists = selectBoxValues.' + $(sel).attr('name') + ';');
                    if (bPropExists) {
                        $(sel).val(bPropExists);
                    }
                    else {
                        $(sel).val('');
                    }

                });
            } else {
                eval('var bPropExists = selectBoxValues.' + $(sel).attr('name') + ';');
                if (bPropExists) {
                    $(sel).val(bPropExists);
                }
            }
        }
    };

    jForms_RefreshDependentSelects = function() {
        var selName = $(this).attr('name');
        opts.coreElement.find('select').each(function() {
            if ($(this).attr('rel').indexOf('/[Form.' + selName) > -1) {
                jForms_RefreshSelect(this);
            }
        });
    };

    var selectBoxValues = {};
    var checkBoxValues = {};

    return this.each(function(i, e) {

        var formUrl = ''
        if (opts.form.indexOf('/') > -1) {
            formUrl = opts.form;
        } else if (opts.form.indexOf(',') > -1) {
            formUrl = '/CMS/File/Resource?Assembly=' + opts.form.split(',')[0] + '&Filename=' + opts.form.split(',')[1];
        }
        else {
            formUrl = '/Forms/' + opts.form + '.tpl';
        }

        $.get(formUrl, {}, function(tpl) {
            $(tpl.split("\n")).each(function(lineIndex, line) {
                if (line.indexOf('{$T.') > -1) {
                    var matches = line.match(/\{\$T\.(.[^\}]*)\}/);
                    if (matches) {
                        requiredResources.push(matches[1]);
                    }
                }
            });

            $.getTranslations(requiredResources, function(json) {

                resources = $.extend(json, resources);

                opts.messagesElement = $('<div class="validationSummary"></div>');
                opts.messagesElement.appendTo($(e));

                // Wrap fields in dummy form
                opts.coreElement = $('<form action="' + opts.url + '" method="' + opts.method + '"></form>');
                opts.coreElement.appendTo($(e));

                opts.coreElement
                    .setTemplateURL(formUrl)
                    .setParam('object', opts.object || {})
                    .processTemplate(resources);

                var modalParent = opts.coreElement.parents('.modalContainer:first');
                if (modalParent.length > 0) {
                    modalParent.find('form').after($('<div class="cmsClear">&nbsp;</div>'));
                }

                // Parse "current" object values into relevant form fields
                // Save values of select boxes and checkboxes for later use
                if (opts.object) {
                    opts.coreElement.find(':input').each(function(i2, e2) {
                        var input = $(this);
                        var fieldVal = opts.object[input.attr('name')];
                        if (input[0].tagName.toLowerCase() == 'select') {
                            eval('var tempVal = { ' + input.attr('name') + ': fieldVal };');
                            selectBoxValues = $.extend(selectBoxValues, tempVal);
                        } else if (input.attr('type').toLowerCase() == 'checkbox') {
                            if (fieldVal && fieldVal.toString() == "true") {
                                eval('var tempVal = { ' + input.attr('name') + ': true };');
                            } else {
                                eval('var tempVal = { ' + input.attr('name') + ': false };');
                            }
                            checkBoxValues = $.extend(checkBoxValues, tempVal);
                        } else if (fieldVal != undefined && fieldVal && fieldVal.indexOf && fieldVal.indexOf('/Date(') > -1) {
                            fieldVal = fieldVal.replace('/Date(', '').replace(')/', '');
                            var date = new Date(parseInt(fieldVal));
                            input.addClass('datePicker');
                            //input.val(date.getFullYear() + '-' + padLeft(date.getMonth(), 2, '0') + '-' + padLeft(date.getDate(), 2, '0') + ' ' + padLeft(date.getHours(), 2, '0') + ':' + padLeft(date.getMinutes(), 2, '0') + ':' + padLeft(date.getSeconds(), 2, '0'));
                            input.val(date.asString('yyyy-mm-dd'));
                        } else if (fieldVal != undefined) {
                            input.val(fieldVal);
                        }
                    });
                }

                // Populate select boxes with options, set selected options
                var timer = 250;
                opts.coreElement
                .find('select')
                .each(function(selIndex, sel) {
                    opts.coreElement.animate({ opacity: 1 }, timer, function() {
                        jForms_RefreshSelect(sel, opts.coreElement);
                    });
                    timer = timer + 100;
                }).each(function(selIndex, sel) {

                });

                opts.coreElement.find('label').each(function(labelIndex, lbl) {
                    if ($(lbl).attr('for').length == 0) {
                        var guid = new Guid();
                        $(lbl).attr('for', guid.generate());
                        $(lbl).parent().find('span').each(function(spanIndex, span) {
                            $($(span).children()[0]).attr('id', $(lbl).attr('for'));
                        });
                    }
                });

                // Set checkboxes to correct initial values
                opts.coreElement.find('input[type=checkbox]').each(function(chkIndex, chk) {
                    eval('chk.checked = checkBoxValues.' + $(chk).attr('name') + ';');
                });

                //opts.coreElement.find('.datePicker').datePicker();

                // Populate hidden fields with form fields
                opts.coreElement.find('input[type=hidden]').each(function(hdnIndex, chk) {
                    eval('chk.checked = checkBoxValues.' + $(chk).attr('name') + ';');
                });

                // Add passed hidden inputs
                if (opts.hiddenFields) {
                    $.each(opts.hiddenFields, function(i, field) {
                        hiddenField = $('<input type="hidden" id="' + i + '" name="' + i + '" value="' + field + '" class="param" />')
                        opts.coreElement.append(hiddenField);
                    });
                }

                if (opts.saveButtonText && opts.saveButtonText.length > 0) {
                    opts.coreElement.find('.saveButton').val(opts.saveButtonText);
                }
                
                // Set up date pickers
                opts.coreElement.find('.datePicker').datepicker({ dateFormat: 'yy-mm-dd' });

                if (opts.onLoaded) {
                    opts.onLoaded();
                }

                opts.coreElement.find('.cancelButton').css('cursor', 'pointer').click(function() {
                    if (opts.onCancel) {
                        opts.onCancel();
                    }
                });

                if (opts.ajaxMode) {
                    opts.coreElement.submit(function() {
                        return false;
                    });

                    opts.coreElement
                    .find('.saveButton')
                    .css('cursor', 'pointer')
                    .click(function() {

                        opts.messagesElement.html('');
                        var obj = {};
                        if (opts.object) {
                            obj = $.extend(obj, opts.object);
                        }

                        var formValues = {};
                        var paramsObj = {};

                        opts.coreElement.find('.formRow :input[type!=button]').each(function(i2, e2) {
                            var input = $(e2);
                            var inputVal = input.val();
                            if (input.attr('type').toLowerCase() == 'checkbox' || input.attr('type').toLowerCase() == 'radio') {
                                var inputChecked = input.attr('checked').toString();

                                if (inputChecked && (inputChecked.toLowerCase() == 'on' || inputChecked.toLowerCase() == 'checked' || inputChecked.toLowerCase() == 'true')) {
                                    if (inputVal.length != 0) {
                                        if (inputVal.toLowerCase() == 'on' || inputVal.toLowerCase() == 'checked' || inputVal.toLowerCase() == 'true') {
                                            inputVal = 'true';
                                        }
                                        else {
                                            // return value
                                        }
                                    }
                                    else {
                                        inputVal = 'true';
                                    }
                                }
                                else if (inputChecked) {
                                    // assume false
                                    if (inputVal.length != 0) {
                                        if (inputVal.toLowerCase() == 'on' || inputVal.toLowerCase() == 'checked' || inputVal.toLowerCase() == 'true' || inputVal.toLowerCase() == 'off' || inputVal.toLowerCase() == 'false') {
                                            inputVal = 'false';
                                        }
                                        else {
                                            inputVal = null;
                                        }
                                    }
                                    else {
                                        inputVal = 'false';
                                    }
                                }
                                else {
                                    if (inputVal.length != 0) {
                                        if (inputVal.toLowerCase() == 'on' || inputVal.toLowerCase() == 'checked' || inputVal.toLowerCase() == 'true' || inputVal.toLowerCase() == 'off' || inputVal.toLowerCase() == 'false') {
                                            inputVal = 'false';
                                        }
                                        else {
                                            inputVal = null;
                                        }
                                    }
                                    else {
                                        inputVal = 'false';
                                    }
                                }
                            }
                            if (inputVal != null) {
                                if (input.hasClass("param")) {
                                    if (paramsObj.hasOwnProperty(input.attr('name')) && paramsObj[input.attr('name')].length != 0)
                                        paramsObj[input.attr('name')] = paramsObj[input.attr('name')] + ',' + inputVal;
                                    else
                                        paramsObj[input.attr('name')] = inputVal;
                                } else {
                                    if (formValues.hasOwnProperty(input.attr('name')) && formValues[input.attr('name')].length != 0)
                                        formValues[input.attr('name')] = formValues[input.attr('name')] + ',' + inputVal;
                                    else
                                        formValues[input.attr('name')] = inputVal;
                                }
                            }
                        });

                        // Pass hidden params
                        opts.coreElement.find('input[type=hidden]').each(function(i2, e2) {
                            if (paramsObj.hasOwnProperty($(e2).attr('name')) && paramsObj[$(e2).attr('name')].length != 0)
                                paramsObj[$(e2).attr('name')] = paramsObj[$(e2).attr('name')] + ',' + $(e2).val();
                            else
                                paramsObj[$(e2).attr('name')] = $(e2).val();
                            if (formValues.hasOwnProperty($(e2).attr('name')) && formValues[$(e2).attr('name')].length != 0)
                                formValues[$(e2).attr('name')] = formValues[$(e2).attr('name')] + ',' + $(e2).val();
                            else
                                formValues[$(e2).attr('name')] = $(e2).val();
                        });

                        // update obj from formValues
                        $.extend(obj, formValues);

                        if (opts.onProceed) {
                            opts.onProceed(obj);
                        }
                        if (opts.url && opts.url.length > 0) {
                            var postData = { object: $.compactJSON(obj) };
                            if (opts.params) {
                                postData = $.extend(postData, opts.params);
                            }
                            postData = $.extend(postData, paramsObj)
                            $.postJSON(opts.url, postData, function(json) {
                                if (json.success) {
                                    if (opts.onSuccess) {
                                        opts.onSuccess(json.result);
                                    }
                                } else {
                                    if (opts.coreElement.find('.validationSummary').length != 0) {
                                        var errs = '';
                                        for (prop in json.errorMessages) {

                                            $(json.errorMessages[prop]).each(function(i, o) {
                                                errs += '<li>';
                                                errs += o;
                                                errs += '</li>';
                                            });
                                        }
                                        opts.coreElement.find('.validationSummary').html('<ul class="errors">' + errs + '</ul>');
                                    }
                                    // Display validation messages
                                    opts.coreElement.find('span .validationMessage').each(function() {
                                        var elm = $(this);
                                        $(elm).html('');
                                        if ($(this).attr('rel').length != 0 && json.errorMessages[$(this).attr('rel')]) {
                                            $(json.errorMessages[$(this).attr('rel')]).each(function() {
                                                $(elm).html($(elm).html() + this + '; ');
                                            });
                                        }
                                    });
                                }
                            });
                        }

                        opts.coreElement.find('input[type=text]:first').focus();
                        return false;
                    });
                }
            });
        });
    });
};

